/**
 * @file       st7789.c
 * @author     wangbing
 * @email      mz8023yt@163.com
 * @version    V1.0
 * @date       2022-03-08
 * @brief      ips lcd panel drvier
 */

#include "st7789.h"
#include <string.h>

void st7789_init(struct st7789* lcd)
{
	int i = 0;

	/* reset sequence */
	/* the spec requires at least 10us */
	lcd->ops.reset(LOW);
	lcd->ops.msleep(100);

	/* the spec requires a maximum wait of 120ms */
	lcd->ops.reset(HIGH);
	lcd->ops.msleep(120);

	struct cmds init[] = {
		{ 0x36, { 0x00 }, 1 },
		{ 0x21, { 0 }, 0 },
		{ 0x3a, { 0x05 }, 1 },
		{ 0xb2, { 0x0c, 0x0c, 0x00, 0x33, 0x33 }, 5 },
		{ 0xb7, { 0x35 }, 1 },
		{ 0xbb, { 0x1f }, 1 },
		{ 0xc0, { 0x2c }, 1 },
		{ 0xc2, { 0x01 }, 1 },
		{ 0xc3, { 0x1d }, 1 },
		{ 0xc4, { 0x20 }, 1 },
		{ 0xc6, { 0x0f }, 1 },
		{ 0xd0, { 0xa4, 0xa1 }, 2 },
		{ 0xe4, { 0x27, 0x00, 0x00 }, 3 },
		{ 0xe0, { 0xd0, 0x00, 0x14, 0x15, 0x13, 0x2c, 0x42, 0x43, 0x4e, 0x09, 0x16, 0x14, 0x18, 0x21 }, 14 },
		{ 0xe1, { 0xd0, 0x00, 0x14, 0x15, 0x13, 0x0b, 0x43, 0x55, 0x53, 0x0c, 0x17, 0x14, 0x23, 0x20 }, 14 },
		{ 0x11, { 0 }, 0 },
		{ 0x29, { 0 }, 0 },
	};

	/* initializing the lcd */
	for (i = 0; i < 17; i++) {
		lcd->ops.i80_reg_write(init[i].cmd, init[i].dats, init[i].nums);
	}

	/* light up backlight */
	lcd->ops.backlight(HIGH);
}

void st7789_rect_fill(struct st7789* lcd, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t* color)
{
	uint8_t cmd = 0x00;
	uint8_t dats[4] = { 0x00 };
	uint32_t nums = 0;
	uint32_t lens = 0;

	/* Column Address Set */
	cmd = 0x2A;
	dats[0] = (x1 + lcd->cfg.fix.xshift) >> 8;
	dats[1] = (x1 + lcd->cfg.fix.xshift) & 0xff;
	dats[2] = (x2 + lcd->cfg.fix.xshift) >> 8;
	dats[3] = (x2 + lcd->cfg.fix.xshift) & 0xff;
	nums = 4;
	lcd->ops.i80_reg_write(cmd, dats, nums);

	/* Row Address Set */
	cmd = 0x2B;
	dats[0] = (y1 + lcd->cfg.fix.yshift) >> 8;
	dats[1] = (y1 + lcd->cfg.fix.yshift) & 0xff;
	dats[2] = (y2 + lcd->cfg.fix.yshift) >> 8;
	dats[3] = (y2 + lcd->cfg.fix.yshift) & 0xff;
	lcd->ops.i80_reg_write(cmd, dats, nums);

	/* Memory Write */
	cmd = 0x2C;
	lens = (x2 - x1 + 1) * (y2 - y1 + 1) * 2;
	lcd->ops.i80_color_write(cmd, color, lens);
}
